package com.lzrj.server;

import com.lzrj.utlis.DeleteFileUtils;
import org.apache.tomcat.jni.OS;
import org.json.JSONObject;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.StandardCharsets;

public class ProcessInfo {

    /**
     * 当前运行时的进程pid
     */
    private static Long processId = null;

    private static File getProcessInfoFile(Integer webPort){
        String userHome = System.getProperty("user.home");
        //String javaHome = System.getProperty("java.home");
        File pInfoFile = new File(userHome + File.separator + ".x_tomcat" + File.separator + "pInfo-"+webPort);
        if (!pInfoFile.getParentFile().exists()){
            pInfoFile.getParentFile().mkdir();
        }
        return pInfoFile;
    }

    public static void removeProcessInfoFile(Integer webPort){
        File processInfoFile = getProcessInfoFile(webPort);
        if (processInfoFile.exists()){
            JSONObject processInfo = getProcessInfo(processInfoFile);
            if (processInfo != null){
                JSONObject config = processInfo.optJSONObject(webPort.toString());
                String basedir = config.optString("basedir");
                File baseFile = new File(basedir);
                DeleteFileUtils.delete(baseFile);
            }
            processInfoFile.delete();
        }
    }

    /**
     * 将进程信息写入文件
     */
    public static void writeProcessInfo(Object webapp,Integer webPort,String basedir){

        long currentProcessId = getCurrentProcessId();

        File pInfoFile = getProcessInfoFile(webPort);

        RandomAccessFile configRwFile = null;
        FileChannel configFileChannel = null;
        FileLock configFileLock = null;
        try {
            configRwFile = new RandomAccessFile(pInfoFile, "rw");
            configFileChannel = configRwFile.getChannel();
            configFileLock = configFileChannel.lock();

            JSONObject configObj;
            if (configRwFile.length() > 0){
                String line ;
                StringBuilder configBuilder = new StringBuilder();
                while (true){
                    line = configRwFile.readLine();
                    if (line == null){
                        break;
                    }
                    configBuilder.append(line);
                }
                configObj = new JSONObject(configBuilder.toString());
            }else {
                configObj = new JSONObject();
            }

            JSONObject proInfoObj = new JSONObject();
            proInfoObj.put("pid",currentProcessId);
            proInfoObj.put("port",webPort);
            proInfoObj.put("webapp",webapp);
            proInfoObj.put("basedir",basedir);
            configObj.put(webPort.toString(),proInfoObj);

            byte[] configBytes = configObj.toString().getBytes(StandardCharsets.UTF_8);

            configRwFile.setLength(0);
            configRwFile.seek(0);
            configRwFile.write(configBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (configFileLock != null){
                    configFileLock.release();
                }
                if (configFileChannel != null){
                    configFileChannel.close();
                }
                if (configRwFile != null){
                    configRwFile.close();
                }
            }catch (IOException ex){
                ex.printStackTrace();
            }
        }
    }


    public static JSONObject getProcessInfo(Integer webPort){
        File processInfoFile = getProcessInfoFile(webPort);
        return getProcessInfo(processInfoFile);
    }

    public static JSONObject getProcessInfo(File processInfoFile){
        StringBuilder configBuilder = readFileContent(processInfoFile);
        if (configBuilder.length() > 0){
            return new JSONObject(configBuilder.toString());
        }
        return null;
    }

    private static StringBuilder readFileContent(File file){
        StringBuilder configBuilder = new StringBuilder();
        BufferedReader fileReader = null;
        try {
            fileReader = new BufferedReader(new FileReader(file));
            String line;
            while ((line = fileReader.readLine()) !=null){
                configBuilder.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fileReader != null){
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return configBuilder;
    }

    /**
     * 获取当前运行时pid
     * @return
     */
    public static long getCurrentProcessId(){
        if (processId == null){
            RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
            String processName = runtimeMXBean.getName();
            String[] processNameInfos = processName.split("@");
            processId = Long.parseLong(processNameInfos[0]);
        }
        return processId;
    }

    public static void killCurrentProcessId(){
        killCmd(getCurrentProcessId());
    }


    public static void killWebPortProcessId(Integer[] webPort){
        for (Integer port : webPort) {
            killWebPortProcessId(port);
        }
    }

    public static void killWebPortProcessId(Integer webPort){
        JSONObject processInfo = getProcessInfo(webPort);
        if (processInfo == null){
            System.err.printf("未找到端口[%s]相关的运行进程 %n",webPort);
            return;
        }
        JSONObject pDetails = processInfo.getJSONObject(webPort.toString());
        long pid = pDetails.optLong("pid");
        // String webapp = pDetails.optString("webapp");
        killCmd(pid);
        System.out.printf("端口[%s]运行进程已成功关闭！%n",webPort);
    }

    public static void killCmd(long pid){
        Runtime runtime = Runtime.getRuntime();

        try {
            if (OS.IS_LINUX || OS.IS_UNIX){
                runtime.exec("kill -15 " + pid);
            }else if (OS.IS_WIN64 || OS.IS_WIN32){
                runtime.exec("taskkill /pid " + pid);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
